package znet

import (
	"bytes"
	"encoding/binary"
	"io"

	"gitee.com/colin0724/zserver/utils"
	"gitee.com/colin0724/zserver/ziface"
)

// Magic(2B) | Len(4B) | Type (1B) | Cmd(2B) | Seq(2B) | Data | Crc(2B)
type BasePack struct {
	Magic uint16 // 0xA097
	Len   uint32
	Type  uint8
	Crc   uint16
}

type BaseMsg struct {
	Cmd  uint16
	Seq  uint16
	Data []byte
}

func (p *BasePack) ReadMsg(r io.Reader) (ziface.IMsg, error) {
	err := binary.Read(r, binary.BigEndian, &p.Magic)
	if err != nil {
		return nil, err
	}

	err = binary.Read(r, binary.BigEndian, &p.Len)
	if err != nil {
		return nil, err
	}

	err = binary.Read(r, binary.BigEndian, &p.Type)
	if err != nil {
		return nil, err
	}

	var m BaseMsg
	err = binary.Read(r, binary.BigEndian, &m.Cmd)
	if err != nil {
		return nil, err
	}

	err = binary.Read(r, binary.BigEndian, &m.Seq)
	if err != nil {
		return nil, err
	}

	m.Data = make([]byte, p.Len-6)
	err = binary.Read(r, binary.BigEndian, &m.Data)
	if err != nil {
		return nil, err
	}

	err = binary.Read(r, binary.BigEndian, &p.Crc)
	if err != nil {
		return nil, err
	}

	return &m, nil
}

func (p *BasePack) CrcSum(m ziface.IMsg) (uint16, error) {
	buff := bytes.NewBuffer([]byte{})
	if err := binary.Write(buff, binary.BigEndian, p.Magic); err != nil {
		return 0, err
	}

	if err := binary.Write(buff, binary.BigEndian, p.Len); err != nil {
		return 0, err
	}

	if err := binary.Write(buff, binary.BigEndian, p.Type); err != nil {
		return 0, err
	}

	mdata, err := m.Encode()
	if err != nil {
		return 0, err
	}

	if err := binary.Write(buff, binary.BigEndian, mdata); err != nil {
		return 0, err
	}

	p.Crc = utils.CrcSum(buff.Bytes())
	return p.Crc, nil
}

func (p *BasePack) Pack(ziface.IMsg) ([]byte, error) {
	return nil, nil
}

func (p *BasePack) Unpack([]byte) (ziface.IMsg, error) {
	return nil, nil
}

func (m *BaseMsg) Encode() ([]byte, error) {
	return nil, nil
}

func (m *BaseMsg) Decode([]byte) error {
	return nil
}

func (m *BaseMsg) GetDataLen() uint32 {
	return uint32(len(m.Data))
}

func (m *BaseMsg) GetMsgId() uint16 {
	return m.Cmd
}

func (m *BaseMsg) GetSeq() uint16 {
	return m.Seq
}

func (m *BaseMsg) GetData() []byte {
	return m.Data
}

func (m *BaseMsg) SetMsgId(id uint16) {
	m.Cmd = id
}

func (m *BaseMsg) SetData(data []byte) {
	m.Data = data
}

func (m *BaseMsg) SetDataLen(l uint32) {
	m.Data = make([]byte, l)
}
